/*

Copyright 2009 Nicola Dal Pont

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Version ${MAJOR_VERSION}.${MINOR_VERSION}${BETA_MARK} Build ${BUILD_NUMBER}

*/

package com.astoolkit.workflow.parsley
{
	
	import com.astoolkit.commons.factory.IPooledFactory;
	import com.astoolkit.commons.factory.IPooledFactoryDelegate;
	import com.astoolkit.commons.factory.PooledFactory;
	import com.astoolkit.workflow.WorkflowEvent;
	import com.astoolkit.workflow.api.*;
	
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	import flash.utils.setTimeout;
	
	import mx.core.IMXMLObject;
	import mx.utils.ArrayUtil;
	
	import org.spicefactory.lib.reflect.ClassInfo;
	import org.spicefactory.parsley.core.context.Context;
	import org.spicefactory.parsley.core.context.provider.Provider;
	import org.spicefactory.parsley.core.messaging.receiver.MessageTarget;
	import org.spicefactory.parsley.core.registry.DynamicObjectDefinition;
	import org.spicefactory.parsley.core.registry.ObjectDefinition;
	import org.spicefactory.parsley.core.scope.Scope;
	import org.spicefactory.parsley.core.scope.ScopeName;
	import org.spicefactory.parsley.processor.messaging.receiver.MessageHandler;

	/**
	 * A wrapper node for Parsley context to declare tasks
	 * that are triggered by messages.<br><br>
	 * The task to be executed can be set as a reference to an IWorkflowTask
	 * in the <code>task</code> property or setting taskRefId to a context's object id.<br><br>
	 * If the referenced context object (the task) is defined as DynamicObject, 
	 * a new instance is created or an instance from the pool is retrieved everytime the trigger message is received.
	 * This is useful when tasks need to be invoked repetedly as
	 * singleton objects would fail if begin() is called when a
	 * task is still executing.
	 */ 
  	[DefaultProperty("task")]
	public class MessageDrivenTaskTrigger implements IMXMLObject
	{
        private var _context : Context;
        
		private var _factory : IPooledFactory;
		
		public var messageType : Class;
		
		public var selector : String;
		
		public var task : IWorkflowTask;
        
        public var taskRefId : String;
		
        public var scope : String  = ScopeName.GLOBAL;
        
		public var taskInputFilter : Object;
		
        private var _id : String;
        
		[Inject]
		public function set context( inContext : Context ) : void
        {
            _context = inContext;
			_factory = new PooledFactory();
			_factory.backupProperties = [ "taskInputFilter" ];
			_factory.delegate = new FactoryDelegate( _context, onTaskComplete );
			registerMessageListener();
        }

        private function registerMessageListener() : void
        {
            var target:MessageTarget 
                = new MessageHandler(
                    Provider.forInstance( this ), 
                    "handler", 
                    selector,
                    ClassInfo.forClass( messageType )
                );
           _context.scopeManager.getScope( scope ).messageReceivers.addTarget( target );
        }
        
        public function initialized( inDocument : Object, inId : String ) : void
		{
			_id = inId;
		}
		
		public function handler( inMessage : Object ) : *
		{
            var actualTask : IWorkflowTask;
            var objDef : ObjectDefinition;
            if( taskRefId )
            {
                 objDef = _context.findDefinition( taskRefId );
                 if(objDef is DynamicObjectDefinition )
					 actualTask = _factory.getInstance( objDef.type.getClass() );
				 else
					 actualTask = IWorkflowTask( _context.getObject( taskRefId ) );
            }
            else if( task is IWorkflowTask )
            {
                objDef = _context.findDefinitionByType( 
                    getDefinitionByName( 
                        getQualifiedClassName( task ) ) as Class );
                if(objDef is DynamicObjectDefinition )
					actualTask = _factory.getInstance( objDef.type.getClass() );
				else
					actualTask = task;

            }
			if( taskInputFilter )
				actualTask.taskInputFilter = taskInputFilter;
			actualTask.taskInput = inMessage;
            actualTask.begin();
		}
		
		private function onTaskComplete( inEvent : WorkflowEvent ) : void
		{
			_factory.release( inEvent.target );
		}
		
		
	}
}

/*
 internal IPooledFactoryDelegate implementation
*/

import com.astoolkit.commons.factory.IPooledFactoryDelegate;
import com.astoolkit.workflow.WorkflowEvent;
import com.astoolkit.workflow.api.IWorkflowTask;

import org.spicefactory.parsley.core.context.Context;

class FactoryDelegate implements IPooledFactoryDelegate
{
	private var _context : Context;
	private var _taskCompleteHandler : Function;
	
	public function onDestroy( inTask : Object ) : void
	{
		IWorkflowTask( inTask ).removeEventListener( WorkflowEvent.COMPLETED, _taskCompleteHandler );
	}
	
	public function newInstance( inClass : Class, inProperties : Object ) : Object
	{
		var outTask : IWorkflowTask = IWorkflowTask( 
			_context.createDynamicObjectByType(
				inClass ).instance );
		outTask.addEventListener( WorkflowEvent.COMPLETED, _taskCompleteHandler );
		return outTask;
	}
	
	public function get delegateInstantiation():Boolean
	{
		return true;
	}
	
	
	public function onRelease( inTask : Object ) : void
	{
		//not implemented
	}
	
	
	public function FactoryDelegate( inContext : Context, inTaskCompleteHandler : Function ) 
	{
		_context = inContext;
		_taskCompleteHandler = inTaskCompleteHandler;
	}
}